/**
 * @auth Ning
 * @purpose MATRIX, MATRIX OPRATION...
 * @date 2009-9-5
 * */	
package extendedmath
{
	import flash.geom.Matrix;
	import flash.geom.Point;

	public class ExtendMatrix
	{
		
		//START...
		
		// get matrix by three points...
		public static function getMatrix(points1:Array,points2:Array):Matrix
		{
			var p1:Point = points1[0];
			
			var p2:Point = points1[1];
			
			var p3:Point = points1[2];
			
			var rP1:Point = points2[0];
			
			var rP2:Point = points2[1];
			
			var rP3:Point = points2[2];
			
			var matrix:Matrix = new Matrix;
			
			matrix.c = ((rP1.x - rP2.x) * (p1.x - p3.x) - (rP1.x - rP3.x) * (p1.x - p2.x)) / ((p1.x - p3.x) * (p1.y - p2.y) - (p1.x - p2.x) * (p1.y - p3.y));
			
			matrix.a = ((rP1.x - rP2.x) * (p1.y - p3.y) - (rP1.x - rP3.x) * (p1.y - p2.y)) / ((p1.x - p2.x) * (p1.y - p3.y) - (p1.x - p3.x) * (p1.y - p2.y));
			
			matrix.tx = rP1.x - matrix.a * p1.x - matrix.c * p1.y;
			
			matrix.d = ((rP1.y - rP2.y) * (p1.x - p3.x) - (rP1.y - rP3.y) * (p1.x - p2.x)) / ((p1.x - p3.x) * (p1.y - p2.y) - (p1.x - p2.x) * (p1.y - p3.y));;
			
			matrix.b = ((rP1.y - rP2.y) * (p1.y - p3.y) - (rP1.y - rP3.y) * (p1.y - p2.y)) / ((p1.x - p2.x) * (p1.y - p3.y) - (p1.x - p3.x) * (p1.y - p2.y));
			
			matrix.ty = rP1.y - matrix.b * p1.x - matrix.d * p1.y;
			
			return matrix;	
			
		}
		
		//static methods...
		static public function createUnitMatrix(den:uint):ExtendMatrix
		{
			
			var temp:Array = new Array;
			
			for(var x:uint = 0; x < den;x++)
			{
				
				
				for(var y:uint = 0; y < den;y++)
				{
					
					
					temp.push(x == y ? 1 : 0);
					
				}
				
				
			}
			
			var matrix:ExtendMatrix = new ExtendMatrix(den,den,temp);
			
			return matrix;
			
		}
		
		
		//PROPERTY...
		private var _rows:Array;
		
		private var _cols:Array;
		
		//CONSTRUCTOR...
		public function ExtendMatrix(xDen:uint,yDen:uint,initData:Array = null)
		{
								
			_rows = new Array;
			
			_cols = new Array;
			
			var row:Array;
			
			var col:Array;
			
			var x:uint;
			
			var y:uint;
			
			for( x = 0; x < xDen; x++)
			{
			
				row = new Array
					
				for( y = 0; y < yDen;y++)
				{
					
					row[y] = initData is Array ? initData[x * yDen + y] : 0;
					
				}
				
				_rows[x] = row;
								
			}
			
			for(y = 0; y < yDen; y++)
			{
			
				col = new Array
					
				for(x = 0; x < xDen;x++)
				{
					
					col[x] = initData is Array ? initData[y * xDen + x] : 0;

				}
				
				_cols[y] = col;
								
			}
			
			
									
		}
		
		
		//METHODS...
		
		//opration...
		
		//all opration for the matrix all elements are Number...
		
		//additional...
		public function add(matrix:ExtendMatrix):ExtendMatrix
		{
			
			var result:ExtendMatrix;
			
			if(rowsCount == matrix.rowsCount && colsCount == matrix.colsCount)
			{
				
				var temp:Array = new Array;
				
				for(var x:uint = 0; x < rowsCount; x++)
				{
									
					for(var y:uint = 0; y < colsCount;y++)
					{
						
						
						temp.push(getElementByIndex(x,y) + matrix.getElementByIndex(x,y));
						
												
					}	
										
				}
				
				result = new ExtendMatrix(rowsCount,colsCount,temp);		
				
			}
			
			
			return result;
			
		}
		
		//subtration...
		public function sub(matrix:ExtendMatrix):ExtendMatrix
		{
			
			var result:ExtendMatrix;
			
			if(rowsCount == matrix.rowsCount && colsCount == matrix.colsCount)
			{
				
				var temp:Array = new Array;
				
				for(var x:uint = 0; x < rowsCount; x++)
				{
									
					for(var y:uint = 0; y < colsCount;y++)
					{
						
						
						temp.push(getElementByIndex(x,y) - matrix.getElementByIndex(x,y));
						
												
					}	
										
				}
				
				result = new ExtendMatrix(rowsCount,colsCount,temp);		
				
			}
			
			
			return result;
			
		}
		
		
		//	multiplication
		public function mul(matrix:ExtendMatrix):ExtendMatrix
		{
			
			var result:ExtendMatrix;
			
			if(colsCount == matrix.rowsCount)
			{
				
				var temp:Array = new Array;
				
				var tempNum:Number;
				
				for(var x:uint = 0; x < rowsCount; x++)
				{
									
					for(var y:uint = 0; y < matrix.colsCount;y++)
					{
												
						tempNum = 0;
						
						for(var i:uint = 0; i < colsCount;i++)
						{
							
							tempNum += getElementByIndex(x,i) * matrix.getElementByIndex(i,y);	
														
						}
						
						temp.push(tempNum);
												
					}	
										
				}
				
				result = new ExtendMatrix(rowsCount,matrix.colsCount,temp);		
				
			}
			
			
			return result;
						
		}	
		
		//return the value of determinant defined by this matrix...
		public function get det():Number
		{
		
			if(rowsCount != colsCount)
			{
				
				return NaN;
				
			}
						
			var addNum:Number = 0;
			
			var subNum:Number = 0;
			
			var addTemp:Number;
			
			var subTemp:Number;
			
			var addIndex:uint;
			
			var subIndex:uint;
			
			for(var y:uint = 0;y < colsCount;y++)
			{
			
				addTemp = 1;
				
				subTemp = 1;
				
				addIndex = y;
				
				subIndex = y;
								
				for(var x:uint = 0; x < rowsCount;x++)
				{
					
																			
					addTemp = addTemp * getElementByIndex(x,addIndex);
					
					subTemp = subTemp * getElementByIndex(x,subIndex);
										
					addIndex = addIndex + 1 >= colsCount ? 0 : addIndex + 1;
					
					subIndex = subIndex == 0 ? colsCount - 1 : subIndex - 1;
					
				}
						
				
				addNum += addTemp;
				
				subNum += subTemp;
				
								
			}
			
			
			return (addNum - subNum);
			
		}
		
		
		//add rows...
		public function addRows(...rows):void
		{
			
			for(var i:uint = 0;i < rows.length;i++)
			{
				
				_rows.push(rows[i]);
				
				for(var y:uint = 0; y < rows[i].length;y++)
				{
					
					_cols[y].push(rows[i][y]);					
					
				}		
				
				
			}
									
		}
		
		
		//add cols...
		public function addCols(...cols):void
		{
		
			for(var i:uint = 0;i < cols.length;i++)
			{
				
				_cols.push(cols[i]);
				
				for(var x:uint = 0; x < cols[i].length;x++)
				{
					
					_rows[x].push(cols[i][x]);					
					
				}		
				
				
			}
			
		}
		
		//get rows count...
		public function get rowsCount():uint
		{
			
			return _rows.length;
			
		}
		
		
		//get cols count...
		public function get colsCount():uint
		{
			
			return _cols.length;
			
		}
		
		//get row by index...
		public function getRowByIndex(index:uint):Array
		{
			
			return _rows[index];
			
		}
		
		//get index by index...
		public function getColByIndex(index:uint):Array
		{
			
			return _cols[index];
			
		}
		
		//get element by index...
		public function getElementByIndex(hIndex:uint,vIndex:uint):*
		{
			
			return _rows[hIndex][vIndex];
			
		}
		
	
		
		//override toString() function...
		public function toString():String
		{
			
			var str:String = "";
			
			var temp:String;
			
			for(var x:uint = 0; x < _rows.length;x++)
			{
				
				temp = "";
				
				for(var y:uint = 0; y < _rows[x].length;y++)
				{
					
					temp += String(_rows[x][y]) + ( y < _rows[x].length - 1 ? " , " : "" );					
					
				}
				
				if(x == 0)
				{
					
					str+= "┌ " + temp + " ┐";
					
				}else if(x == _rows.length - 1)
				{
					
					str+= "└ " + temp + " ┘";
					
				}else{
					
					
					str += "│ " + temp + " │";					
					
				}
				
				str += "\n";			
				
			} 
			
			return str;
		}
		
				
		
		//END
	}
}